/**
 *
 * Created by huangxuan2046 on 16/8/6.
 */



(function () {

  // 图像相关的计算类
  var gutils = {
    /**
     * 通过得到对象的rect.
     * left top 是绝对的.只要统一在一个坐标系里面就好了
     */
    getRect: function (dom) {
      return dom.getBoundingClientRect();
    },
    /**
     * 用jquery修订了偏差的值
     */
    getFixedRect: function (selector) {
      var $dom = $(selector);
      if ($dom.length) {
        var width = $dom.width();
        var height = $dom.height();
        var offset = $dom.offset();
        return {
          left: offset.left,
          right: offset.left + width,
          top: offset.top,
          bottom: offset.top + height,
          width: width,
          height: height
        }
      }
      return null;
    },
    /**
     *  用jquery 修订了偏差的相对值
     */
    getRelativeRect: function (relativeSelector, selector) {
      var $relativeSelector = $(relativeSelector);
      var $selector = $(selector);
      var relativeOffset = $relativeSelector.offset();
      var offset = $selector.offset();
      var width = $selector.width();
      var height = $selector.height();

      var left = offset.left - relativeOffset.left;
      var top = offset.top - relativeOffset.top;
      return {
        left: left,
        right: left + width,
        top: top,
        bottom: top + height,
        width: width,
        height: height
      }
    },
    getUnionRect: function (root, dom) {

    },

    /**
     *
     * @param left 目标作用域的x轴坐标
     * @param top
     * @param rect
     */
    getRelativeRect: function (left, top, rect) {

    },
    // 是不是相交
    intersectRect: function (r1, r2) {
      return !(r2.left > r1.right ||
      r2.right < r1.left ||
      r2.top > r1.bottom ||
      r2.bottom < r1.top);
    }
  }

  var treeIdSed = 0;

  function createTreeId (parent) {
    if (!parent) {
      parent = "tree";
    }
    return {
      $$treeId: parent + "/" + treeIdSed++
    }

  }

  function recalcTreeId (parent, start) {
    if (start) {
      start.$$treeId = parent + "/" + treeIdSed++;
      start.$$api.dom.html("treeid:" + start.$$treeId + "  ");
      _.each(start.components, function (component) {
        recalcTreeId(start.$$treeId, component);
      })
    }

  }

  var zIndex = 0;

  function topZindex () {
    return zIndex++;
  }

  var snap = {
    x: 17,
    y: 17,
    getX: function (x) {
      return snap.x * x;
    },
    getY: function (y) {
      return snap.y * y;
    },
    getRow: function (x) {
      return Math.floor(x / snap.x);
    },
    getCol: function (y) {
      return Math.floor(y / snap.y);
    }
  };

  var csses = {
    zone: "can-zone",
    comp: "can-comp",
    container: "can-container"
  };

  var api = {
    born: function (el, config) {

      var $$selection = $("<div>").css({
        position: "absolute",
        border: "2px dashed yellow"
      });

      var baseApi = {
        select: function () {
          this.model.selected = true;
          this.dom.addClass("selected");
          createHelperLine(this.dom);
        },
        unSelect: function () {
          this.model.selected = false;
          this.dom.removeClass("selected");
          removeHelperLine(this.dom);
        },
        isSelected: function () {
          return this.model.selected;
        },
        setParent: function (parentModel) {
          var me = this;
          if (this.model) {
            if (parentModel == this.model) {
              return;
            }
            var oldParent = this.model.parent;

            function put () {
              me.model.parent = parentModel;
              if (!_.includes(parentModel.components, me.model)) {
                parentModel.components.push(me.model);
              }

            }

            if (oldParent !== parentModel) {
              var components = oldParent.components;
              _.remove(components, this.model);
              put();
              recalcTreeId(parentModel.$$treeId, me.model);
            } else {
              put();
            }

          }
        },
        move: function (dx, dy) {
          var me = this;
          var curPosition = me.dom.position();
          me.dom.css({
            left: curPosition.left + dx,
            top: curPosition.top + dy
          });
          if (me.model) {
            var components = me.model.components;
            _.each(components, function (component) {
              component.$$api.move(dx, dy);
            })

          }
        },
        // 直接通过页面的绝对位置来移动
        moveToPage: function (pageX, PageY) {
          var offset = this.dom.offset();
          // todo 方向计算模型
          var dx = pageX - offset.left;
          var dy = pageY - offset.top;
          this.move(dx, dy);
        },
        // 通过相对位置来移动
        moveTo: function (relativeX, relativeY) {
          var offset = this.dom.offsetParent();
          var dx = relativeX - offset.left;
          var dy = relativeY - offset.top;
          this.move(dx, dy);
        },
        setZIndex: function (index) {

        },
        getZIndex: function () {
          return this.dom.css("zIndex") * 1;
        }
      };

      function loadModel (model, parentModel, context) {
        if (model.$$api) {
          return model;
        }
        var baseModel = {
          container: model.container,
          $$selected: false,
          $$api: undefined,
          $$rootModel: rootModel,
          appendChild: function (model) {
            if (!_.isArray(model)) {
              model = [ model ];
            }
            var me = this;
            _.each(model, function (m) {
              var resultModel = loadModel(m, me, context);
              resultModel.$$api.setParent(me);
            })

            return this;
          },
          remove: function (model) {
          },
          move: function (dx, dy) {
            this.$$api.move(dx, dy);
          },
          init: function () {
            var realW = snap.getX(this.sizeX);
            var realH = snap.getX(this.sizeY);
            var $dom = this.$$api.dom;
            $dom.css({

              left: snap.getX(this.row || 0),
              top: snap.getY(this.col || 0),
              position: "absolute",
              border: "1px solid #ccc",
              width: realW,
              height: realH
            });
            $dom.addClass(csses.zone);
            $dom.addClass(csses.comp);
            if (this.container) {
              $dom.addClass(csses.container);
            }
            var dom = $dom[ 0 ];
            dom.$$api = this.$$api;
            //debugger;
            var me = this;

            if (me.container) {
              $dom.on("dblclick", function () {
                selectTheComponents([ me ])
              })
            } else {
              $dom.on("mousedown", function () {
                if (me.$$api.isSelected()) {

                } else {
                  selectTheComponents([ me ])
                }

              })
            }

            interact(dom)
              .draggable({
                // enable inertial throwing
                inertia: false,
                // keep the element within the area of it's parent
                restrict: {
                  restriction: function () {
                    return me.$$rootModel.$$api.dom[ 0 ];
                  },
                  endOnly: true,
                  elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
                },
                // enable autoScroll
                autoScroll: true,
                onstart: function (event) {
                  $dom.removeClass("drop-target");
                  if (me.$$api.isSelected()) {

                  } else {

                  }
                },
                // call this function on every dragmove event
                onmove: function (event) {
                  if (me.$$api.isSelected()) {
                    selectToMove(event.dx, event.dy, me);
                  } else {

                  }

                },
                // call this function on every dragend event
                onend: function (event) {

                }
              });

            interact(dom).dropzone({
              accept: "." + csses.zone,
              overlap: "pointer",
              checker: function (dragEvent,         // related dragmove or dragend
                                 event,             // Touch, Pointer or Mouse Event
                                 dropped,           // bool default checker result
                                 dropzone,          // dropzone Interactable
                                 dropElement,       // dropzone elemnt
                                 draggable,         // draggable Interactable
                                 draggableElement) {
                var result = dropped;
                var dropApi = dropElement.$$api;
                var dragApi = draggableElement.$$api;

                if (_.startsWith(dropApi.model.$$treeId, dragApi.model.$$treeId)) {
                  return false;
                }
                // 只有容器可以放东西
                if (dropApi.model.container != true) {
                  return false;
                }
                if (dropped) {
                  //var dragRect = draggable.getRect(draggableElement);
                  //var dropRect = dropzone.getRect(dropElement);

                  //console.info(dropApi.model.$$treeId, dragApi.model.$$treeId);
                }

                return result;
              },
              ondragenter: function (event) {
                var target = event.target;
                $(target).addClass("drop-target");
              },
              ondragleave: function (event) {
                var target = event.target;
                $(target).removeClass("drop-target");
              },
              ondrop: function (event) {
                var relatedTarget = event.relatedTarget;
                var target = event.target;
                $(target).removeClass("drop-target");
                selectToDrop(relatedTarget.$$api.model, me);
              }
            })

          }
        }
        var resultModel;
        if (model) {
          var $$api = _.assign({
            dom: $("<div>")
          }, baseApi);
          resultModel = _.assign(model, baseModel, {
            parent: parentModel,
            components: model.components || [],
            $$api: $$api
          }, createTreeId(parentModel && parentModel.$$treeId));
          if (!parentModel) {
            // root
            resultModel.$$rootModel = resultModel;
          } else {
            resultModel.$$rootModel = rootModel;
          }
          $$api.model = resultModel;

          $$api.dom.css({
            zIndex: topZindex()
          });
          $$api.dom.html("treeid:" + resultModel.$$treeId + "  ");

          _.each(model.components, function (component) {
            loadModel(component, resultModel, context);
          });

          context.add($$api.dom);
        } else {
          throw new Error("args 不对");
        }
        resultModel.init();
        return resultModel;
      }

      var $el = $(el).css({ position: "relative", height: "100%", width: 600 });

      $el.append($$selection);
      rootOffset = $el.offset();
      var rootModel = loadModel({
        container: true,
        sizeX: config.sizeX,
        sizeY: config.sizeY
      }, null, {
        $el: $el,
        rootOffset: rootOffset,
        add: function ($app) {
          $el.append($app);
        }
      });

      var start = undefined;

      $el.on("mousedown", function (e) {
        var comp = $(e.target).closest("." + csses.comp);
        var compDom = comp[ 0 ];
        if (compDom && compDom.$$api.isSelected()) {
          return;
        }

        if (!compDom.$$api.model.container) {
          return;
        }
        clearSelectTheComponents();

        start = {
          // 当前选中的容器
          currentStartContainer: comp
        };
        start.pageX = e.pageX;
        start.pageY = e.pageY;
        start.x = e.pageX - rootOffset.left;
        start.y = e.pageY - rootOffset.top;
        $$selection.show().css({
          left: start.x,
          top: start.y,
          width: 0,
          height: 0
        })

      });
      $el.on("mousemove", function (e) {

        if (start) {
          var width = e.pageX - start.pageX;
          var height = e.pageY - start.pageY;
          $$selection.css("transform-origin", "left top");

          if (width >= 0) {
            if (height >= 0) {
              $$selection.css("transform", "rotateY(0deg)");
            } else {
              $$selection.css("transform", "rotateY(0deg) rotateX(180deg)");
            }
          } else {
            if (height >= 0) {
              $$selection.css("transform", "rotateY(180deg) rotateX(0deg)");
            } else {
              $$selection.css("transform", "rotateY(180deg) rotateX(180deg)");
            }
          }

          //transform:rotateX(120deg);
          $$selection.css({
            width: Math.abs(width),
            height: Math.abs(height)
          });
        }

      });

      $el.on("mouseup", function (e) {
        if (start) {
          var container = start.currentStartContainer[ 0 ];
          if (container) {
            var components = container.$$api.model.components;
            var selectRect = gutils.getRect($$selection[ 0 ]);
            var selecteds = _.filter(components, function (component) {
              var rect = gutils.getRect(component.$$api.dom[ 0 ]);
              return gutils.intersectRect(selectRect, rect);
            })
            selectTheComponents(selecteds);
          }
        }
        $$selection.hide();
        start = undefined;
      })

      function createHelperLine ($dom) {
        removeHelperLine($dom);
        $dom.append($("<div></div>").addClass("helper-line helper-line-e"));
        $dom.append($("<div></div>").addClass("helper-line helper-line-n"));
        $dom.append($("<div></div>").addClass("helper-line helper-line-w"));
        $dom.append($("<div></div>").addClass("helper-line helper-line-s"));
      }

      function removeHelperLine ($dom) {
        $dom.find(".helper-line").remove();
      }

      // 是组件处于选择模式,可以统一加入组合支持
      function selectTheComponents (components) {
        if (!_.isArray(components)) {
          components = [ components ];
        }
        clearSelectTheComponents();
        _.each(components, function (component) {
          component.$$api.select();
        })
        rootApi.currentSelection = {
          items: components
        }
      }

      function clearSelectTheComponents () {
        if (rootApi.currentSelection) {
          _.each(rootApi.currentSelection.items, function (item) {
            item.$$api.unSelect();
          })
        }
      }

      function selectToMove (dx, dy, dragItem) {
        dragItem.move(dx, dy);
        if (rootApi.currentSelection) {
          var otherButNotMe = _.filter(rootApi.currentSelection.items, function (item) {
            return item != dragItem;
          })
          _.each(otherButNotMe, function (component) {
            component.$$api.move(dx, dy);
          })
        }
      }

      function getRectByItem (item) {
        return gutils.getRect(item.$$api.dom[ 0 ]);
      }

      function selectToDrop (dragItem, dropItem) {
        dragItem.$$api.setParent(dropItem);
        if (rootApi.currentSelection) {
          var otherButNotMe = _.filter(rootApi.currentSelection.items, function (item) {
            return item != dragItem;
          })

          var containers = getAllContainer();

          function findTheRightContainer (item) {
            return getTopContainer(containers, getRectByItem(item));
          }

          _.each(otherButNotMe, function (component) {
            var parentItem = findTheRightContainer(component);
            if (parentItem) {
              component.$$api.setParent(parentItem);
            }
          })
        }
      }

      function getAllContainer () {
        var containers = [];
        $el.find("." + csses.container).each(function (i, itemDom) {
          containers.push(itemDom.$$api.model);
        })
        return containers;
      }

      function getTopContainer (containers, rect) {
        return _(containers).filter(function (container) {
          return gutils.intersectRect(rect, getRectByItem(container));
        }).maxBy(function (item) {
          return item.$$api.dom.css("zIndex") * 1;
        })
      }

      window.rootModel = rootModel;

      var rootApi = {
        currentSelection: null,
        groups: [],
        model: rootModel,
        put: function (pageX, pageY, putFn) {
          var relative = rootApi.getRelativeOffset(pageX, pageY);

          if (relative.left > 0 && relative.top > 0) {
            var containers = getAllContainer();
            var top = getTopContainer(containers, {
              left: pageX,
              right: pageX + 1,
              top: pageY,
              bottom: pageY + 1,
              width: 1,
              height: 1
            })
            if (top) {
              if (_.isFunction(putFn)) {
                putFn(top, {
                  row: snap.getRow(relative.left),
                  col: snap.getCol(relative.top)
                });
              }
            }
          }
        },
        getRelativeOffset: function (x, y) {
          //视图
          var rootOffset = $el.offset();
          return {
            left: x - rootOffset.left,
            top: y - rootOffset.top
          }
        },
        leftAlignSelection(){
          if (rootApi.currentSelection) {
            var items = rootApi.currentSelection.items;

            var leftItem = _.minBy(items, function (item) {
              return getRectByItem(item).left;
            })
            if (leftItem) {
              var leftRect = gutils.getRect(leftItem.$$api.dom[ 0 ]);

              _.each(items, function (item) {
                if (item != leftItem) {
                  var itemRect = gutils.getRect(item.$$api.dom[ 0 ]);
                  var dx = leftRect.left - itemRect.left;
                  item.$$api.move(dx, 0);
                }
              })
            }

          }
        },
        rightAlignSelection(){
          if (rootApi.currentSelection) {
            var items = rootApi.currentSelection.items;

            var rightItem = _.maxBy(items, function (item) {
              return getRectByItem(item).right;
            })
            if (rightItem) {
              var rect = getRectByItem(rightItem.$$api.dom[ 0 ]);
              var right = rect.right;
              _.each(items, function (item) {
                if (rightItem != item) {
                  var itemRect = gutils.getRect(item.$$api.dom[ 0 ]);
                  var dx = right - itemRect.right;
                  item.$$api.move(dx, 0);
                }
              })
            }

          }
        }
      }
      return rootApi;
    }
  }

  window.can = api;
})();

function dragMoveListener (event) {
  var target = event.target,
  // keep the dragged position in the data-x/data-y attributes
    x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
    y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

  // translate the element
  target.style.webkitTransform =
    target.style.transform =
      'translate(' + x + 'px, ' + y + 'px)';

  // update the posiion attributes
  target.setAttribute('data-x', x);
  target.setAttribute('data-y', y);
}

// this is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener;

var test = {
  test1: function () {
    var root = window.can.born("#root", {
      sizeX: 50,
      sizeY: 40
    })
    window.rootApi = root;
    var rootModel = root.model;
    var cs = {
      container: true,
      sizeX: 20,
      sizeY: 15,
      components: [ {
        container: true,
        sizeX: 10,
        sizeY: 10,
        components: [ {
          sizeX: 4,
          sizeY: 4
        } ]
      } ]
    };

    for (var i = 0; i < 200; i++) {
      cs.components.push({
        sizeX: 3,
        sizeY: 3
      });
    }
    rootModel.appendChild(cs)
  },
  test2: function () {
    $(".controls div[ref]").each(function (index, item) {
      var $item = $(item);
      var ref = $item.attr("ref");

      var map = {
        label: function (top, moreInfo) {
          top.appendChild({
            row: moreInfo.row,
            col: moreInfo.col,
            sizeX: 3,
            sizeY: 3
          })
        },
        card_layout: function () {

        },
        border_layout: function () {

        },
        line_layout: function () {

        },
        container: function (top, moreInfo) {
          top.appendChild({
            container: true,
            row: moreInfo.row,
            col: moreInfo.col,
            sizeX: 8,
            sizeY: 8
          })
        },
        tab: function () {

        }
      }

      //var $clone = $item.clone().css("position", "absolute");
      //$item.on("mouseup", function () {
      //  $clone.remove();
      //})
      //$("body").append($clone);

      var thisOffset = $item.offset();
      var $clone;
      interact(this)
        .draggable({
          manualStart: true,
          onmove: dragMoveListener,
          onend: function (event) {
            if ($clone) {
              window.rootApi.put(event.pageX, event.pageY, function (top, moreInfo) {
                if (_.isFunction(map[ ref ])) {
                  map[ ref ](top, moreInfo);
                }

              });
              $clone.remove()
            }
          }
        })
        .on('move', function (event) {
          var interaction = event.interaction;
          event.preventDefault();
          // if the pointer was moved while being held down
          // and an interaction hasn't started yet
          if (interaction.pointerIsDown && !interaction.interacting()) {
            var original = event.currentTarget,
            // create a clone of the currentTarget element
              clone = event.currentTarget.cloneNode(true);
            $clone = $(clone);
            // insert the clone to the page
            // TODO: position the clone appropriately
            document.body.appendChild(clone);
            $clone && $clone.css({
              "position": "absolute",
              left: event.pageX,
              top: event.pageY
            })

            // start a drag interaction targeting the clone
            interaction.start({ name: 'drag' },
              event.interactable,
              clone);
          }

        });

    })
  },
  test3: function () {
    var map = {
      leftAlign: function () {
        rootApi.leftAlignSelection();
      },
      rightAlign: function () {
        // todo 左右对齐都应该使用move
        rootApi.rightAlignSelection();
      }

    };
    _.each(map, function (value, key) {
      $(".tool button[ref=" + key + "]").on("click", function () {
        if (map[ key ]) {
          map[ key ]();
        }
      });
    })
  }

}

function runTest (setUp) {
  var i = 1;
  var r = undefined;
  while ((r = test[ "test" + i++ ])) {

    if (setUp) {
      setUp();
    }
    r();

  }
}

runTest(function () {
  //$("body").empty().append("<div id='root'></div>");
});

// 想清楚第一次初始


